<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="ReSpec 35.6.0">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<style>
dfn{cursor:pointer}
.dfn-panel{position:absolute;z-index:35;min-width:300px;max-width:500px;padding:.5em .75em;margin-top:.6em;font-family:"Helvetica Neue",sans-serif;font-size:small;background:#fff;background:var(--indextable-hover-bg,#fff);color:#000;color:var(--text,#000);box-shadow:0 1em 3em -.4em rgba(0,0,0,.3),0 0 1px 1px rgba(0,0,0,.05);box-shadow:0 1em 3em -.4em var(--tocsidebar-shadow,rgba(0,0,0,.3)),0 0 1px 1px var(--tocsidebar-shadow,rgba(0,0,0,.05));border-radius:2px}
.dfn-panel:not(.docked)>.caret{position:absolute;top:-9px}
.dfn-panel:not(.docked)>.caret::after,.dfn-panel:not(.docked)>.caret::before{content:"";position:absolute;border:10px solid transparent;border-top:0;border-bottom:10px solid #fff;border-bottom-color:var(--indextable-hover-bg,#fff);top:0}
.dfn-panel:not(.docked)>.caret::before{border-bottom:9px solid #a2a9b1;border-bottom-color:var(--indextable-hover-bg,#a2a9b1)}
.dfn-panel *{margin:0}
.dfn-panel b{display:block;color:#000;color:var(--text,#000);margin-top:.25em}
.dfn-panel ul a[href]{color:#333;color:var(--text,#333)}
.dfn-panel>div{display:flex}
.dfn-panel a.self-link{font-weight:700;margin-right:auto}
.dfn-panel .marker{padding:.1em;margin-left:.5em;border-radius:.2em;text-align:center;white-space:nowrap;font-size:90%;color:#040b1c}
.dfn-panel .marker.dfn-exported{background:#d1edfd;box-shadow:0 0 0 .125em #1ca5f940}
.dfn-panel .marker.idl-block{background:#8ccbf2;box-shadow:0 0 0 .125em #0670b161}
.dfn-panel a:not(:hover){text-decoration:none!important;border-bottom:none!important}
.dfn-panel a[href]:hover{border-bottom-width:1px}
.dfn-panel ul{padding:0}
.dfn-panel li{margin-left:1em}
.dfn-panel.docked{position:fixed;left:.5em;top:unset;bottom:2em;margin:0 auto;max-width:calc(100vw - .75em * 2 - .5em - .2em * 2);max-height:30vh;overflow:auto}
</style>
    
    
<meta name="color-scheme" content="light dark">
    
<title>Design Tokens Technical Reports 2025.10</title>
    
<meta name="color-scheme" content="light-dark">
    
    
  
<style id="respec-mainstyle">
@keyframes pop{
0%{transform:scale(1,1)}
25%{transform:scale(1.25,1.25);opacity:.75}
100%{transform:scale(1,1)}
}
a.internalDFN{color:inherit;border-bottom:1px solid #99c;text-decoration:none}
a.externalDFN{color:inherit;border-bottom:1px dotted #ccc;text-decoration:none}
a.bibref{text-decoration:none}
.respec-offending-element:target{animation:pop .25s ease-in-out 0s 1}
.respec-offending-element,a[href].respec-offending-element{text-decoration:red wavy underline}
@supports not (text-decoration:red wavy underline){
.respec-offending-element:not(pre){display:inline-block}
.respec-offending-element{background:url() bottom repeat-x}
}
#references :target{background:#eaf3ff;animation:pop .4s ease-in-out 0s 1}
cite .bibref{font-style:italic}
a[href].orcid{padding-left:4px;padding-right:4px}
a[href].orcid>svg{margin-bottom:-2px}
ol.tof,ul.tof{list-style:none outside none}
.caption{margin-top:.5em;font-style:italic}
#issue-summary>ul{column-count:2}
#issue-summary li{list-style:none;display:inline-block}
details.respec-tests-details{margin-left:1em;display:inline-block;vertical-align:top}
details.respec-tests-details>*{padding-right:2em}
details.respec-tests-details[open]{z-index:999999;position:absolute;border:thin solid #cad3e2;border-radius:.3em;background-color:#fff;padding-bottom:.5em}
details.respec-tests-details[open]>summary{border-bottom:thin solid #cad3e2;padding-left:1em;margin-bottom:1em;line-height:2em}
details.respec-tests-details>ul{width:100%;margin-top:-.3em}
details.respec-tests-details>li{padding-left:1em}
.self-link:hover{opacity:1;text-decoration:none;background-color:transparent}
aside.example .marker>a.self-link{color:inherit}
.header-wrapper{display:flex;align-items:baseline}
:is(h2,h3,h4,h5,h6):not(#toc>h2,#abstract>h2,#sotd>h2,.head>h2){position:relative;left:-.5em}
:is(h2,h3,h4,h5,h6):not(#toch2)+a.self-link{color:inherit;order:-1;position:relative;left:-1.1em;font-size:1rem;opacity:.5}
:is(h2,h3,h4,h5,h6)+a.self-link::before{content:"§";text-decoration:none;color:var(--heading-text)}
:is(h2,h3)+a.self-link{top:-.2em}
:is(h4,h5,h6)+a.self-link::before{color:#000}
@media (max-width:767px){
dd{margin-left:0}
}
@media print{
.removeOnSave{display:none}
}
</style>
<meta name="description" content="Design tokens are indivisible pieces of a design system such as colors,
        spacing, typography scale.">
<link rel="canonical" href="https://www.designtokens.org/TR/2025.10/">
<style>
var:hover{text-decoration:underline;cursor:pointer}
var.respec-hl{color:var(--color,#000);background-color:var(--bg-color);box-shadow:0 0 0 2px var(--bg-color)}
@media (prefers-color-scheme:dark){
var.respec-hl{filter:saturate(.9) brightness(.9)}
}
var.respec-hl-c1{--bg-color:#f4d200}
var.respec-hl-c2{--bg-color:#ff87a2}
var.respec-hl-c3{--bg-color:#96e885}
var.respec-hl-c4{--bg-color:#3eeed2}
var.respec-hl-c5{--bg-color:#eacfb6}
var.respec-hl-c6{--bg-color:#82ddff}
var.respec-hl-c7{--bg-color:#ffbcf2}
@media print{
var.respec-hl{background:0 0;color:#000;box-shadow:unset}
}
</style>
<style>
var{position:relative;cursor:pointer}
var[data-type]::after,var[data-type]::before{position:absolute;left:50%;top:-6px;opacity:0;transition:opacity .4s;pointer-events:none}
var[data-type]::before{content:"";transform:translateX(-50%);border-width:4px 6px 0 6px;border-style:solid;border-color:transparent;border-top-color:#222}
var[data-type]::after{content:attr(data-type);transform:translateX(-50%) translateY(-100%);background:#222;text-align:center;font-family:"Dank Mono","Fira Code",monospace;font-style:normal;padding:6px;border-radius:3px;color:#daca88;text-indent:0;font-weight:400}
var[data-type]:hover::after,var[data-type]:hover::before{opacity:1}
</style>
<script id="initialUserConfig" type="application/json">{
  "specStatus": "CG-FINAL",
  "group": "design-tokens",
  "thisVersion": "https://www.designtokens.org/TR/2025.10/",
  "latestVersion": "https://www.designtokens.org/TR/2025.10/",
  "prevVersion": null,
  "edDraftURI": null,
  "editors": [
    {
      "name": "Louis Chenais",
      "url": "https://bsky.app/profile/lucho.cool"
    },
    {
      "name": "Mike Kamminga",
      "url": "https://x.com/mikekamminga"
    },
    {
      "name": "Kathleen McMahon",
      "url": "https://kathleenmcmahon.dev"
    },
    {
      "name": "Drew Powers",
      "url": "https://pow.rs"
    },
    {
      "name": "Matthew Ström-Awn",
      "url": "https://matthewstrom.com"
    },
    {
      "name": "Donna Vitan",
      "url": "https://www.donnavitan.com"
    }
  ],
  "authors": [
    {
      "name": "Daniel Banks",
      "url": "https://x.com/dbanksDesign"
    },
    {
      "name": "Esther Cheran",
      "url": "https://github.com/esthercheran"
    },
    {
      "name": "Andrew L’Homme"
    },
    {
      "name": "Ayesha Mazrana (Mazumdar)",
      "url": "https://x.com/AyeshaKMaz"
    },
    {
      "name": "James Nash",
      "url": "https://cirrus.twiddles.com"
    },
    {
      "name": "Adekunle Oduye",
      "url": "https://www.adekunleoduye.com"
    },
    {
      "name": "Kevin Powell",
      "url": "https://x.com/kevinmpowell"
    },
    {
      "name": "Lilith Wittmann",
      "url": "https://github.com/LilithWittmann"
    }
  ],
  "github": {
    "repoURL": "https://github.com/design-tokens/community-group",
    "branch": "main"
  },
  "tocIntroductory": true,
  "logos": [
    {
      "src": "/assets/dtcg-logo-on-color.svg",
      "url": "https://www.designtokens.org",
      "alt": "Design Tokens Community Group",
      "width": 128,
      "height": 128,
      "id": "dtcg-logo"
    }
  ],
  "publishISODate": "2025-10-28T00:00:00.000Z",
  "generatedSubtitle": "Final Community Group Report 28 October 2025"
}</script>
<link rel="stylesheet" href="https://www.w3.org/StyleSheets/TR/2021/cg-final">
<link rel="stylesheet" media="(prefers-color-scheme: dark)" href="https://www.w3.org/StyleSheets/TR/2021/dark.css"></head>

  <body class="h-entry informative"><div class="head">
    <p class="logos"><a class="logo" href="https://www.designtokens.org"><img crossorigin="" alt="Design Tokens Community Group" height="128" id="dtcg-logo" src="/assets/dtcg-logo-on-color.svg" width="128">
  </a></p>
    <h1 id="title" class="title">Design Tokens Technical Reports 2025.10</h1> 
    <p id="w3c-state">
      <a href="https://www.w3.org/standards/types#reports">Final Community Group Report</a>
      <time class="dt-published" datetime="2025-10-28">28 October 2025</time>
    </p>
    <dl>
      <dt>This version:</dt><dd>
              <a class="u-url" href="https://www.designtokens.org/TR/2025.10/">https://www.designtokens.org/TR/2025.10/</a>
            </dd>
      <dt>Latest published version:</dt><dd>
              <a href="https://www.designtokens.org/TR/2025.10/">https://www.designtokens.org/TR/2025.10/</a>
            </dd>
      
      
      
      
      
      <dt>Editors:</dt><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://bsky.app/profile/lucho.cool">Louis Chenais</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://x.com/mikekamminga">Mike Kamminga</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://kathleenmcmahon.dev">Kathleen McMahon</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://pow.rs">Drew Powers</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://matthewstrom.com">Matthew Ström-Awn</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://www.donnavitan.com">Donna Vitan</a>
  </dd>
      
      <dt>Authors:</dt><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://x.com/dbanksDesign">Daniel Banks</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://github.com/esthercheran">Esther Cheran</a>
  </dd><dd class="editor p-author h-card vcard">
    <span class="p-name fn">Andrew L’Homme</span>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://x.com/AyeshaKMaz">Ayesha Mazrana (Mazumdar)</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://cirrus.twiddles.com">James Nash</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://www.adekunleoduye.com">Adekunle Oduye</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://x.com/kevinmpowell">Kevin Powell</a>
  </dd><dd class="editor p-author h-card vcard">
    <a class="u-url url p-name fn" href="https://github.com/LilithWittmann">Lilith Wittmann</a>
  </dd>
      <dt>Feedback:</dt><dd>
        <a href="https://github.com/design-tokens/community-group/">GitHub design-tokens/community-group</a>
        (<a href="https://github.com/design-tokens/community-group/pulls/">pull requests</a>,
        <a href="https://github.com/design-tokens/community-group/issues/new/choose">new issue</a>,
        <a href="https://github.com/design-tokens/community-group/issues/">open issues</a>)
      </dd>
      
    </dl>
    
    
   <p class="copyright">
          <a href="https://www.w3.org/policies/#copyright">Copyright</a>
          ©
          2025
          
          the Contributors to the Design Tokens Resolver Module 2025.10
          Specification, published by the
          <a href="https://www.w3.org/groups/cg/design-tokens">Design Tokens Community Group</a> under the
          <a href="https://www.w3.org/community/about/agreements/fsa/">W3C Community Final Specification Agreement (FSA)</a>. A human-readable
                <a href="https://www.w3.org/community/about/agreements/fsa-deed/">summary</a>
                is available.
              
        </p>
    <hr title="Separator for header">
  </div>
    
    <section id="abstract" class="introductory"><h2>Abstract</h2>
      <p>
        Design tokens are indivisible pieces of a design system such as colors,
        spacing, typography scale.
      </p>
      <p>
        Design tokens were created by the Salesforce design system team, and the
        name comes from them (<a href="https://x.com/jonnyl">Jon</a> &amp;
        <a href="https://x.com/jina">Jina</a>).
      </p>
    </section>
    <section id="sotd" class="introductory"><h2>Status of This Document</h2><p>
      This specification was published by the
      <a href="https://www.w3.org/groups/cg/design-tokens">Design Tokens Community Group</a>. It is not a W3C Standard nor is it
      on the W3C Standards Track.
      
            Please note that under the
            <a href="https://www.w3.org/community/about/agreements/final/">W3C Community Final Specification Agreement (FSA)</a>
            other conditions apply.
          
      Learn more about
      <a href="https://www.w3.org/community/">W3C Community and Business Groups</a>.
    </p>
      <p>
        This section describes the status of this document at the time of its
        publication. Other documents may supersede this document. A list of
        current W3C Community Group reports and the latest revision of this
        report can be found in the W3C Community Group reports index at
        <a href="https://www.w3.org/community/reports/">https://www.w3.org/community/reports/</a>.
      </p>
      <p>
        This document was published by the DTCG as a
        <a href="https://www.w3.org/policies/process/#RecsCR">Candidate Recommendation</a>
        following the definitions provided by the W3C process. Contributions to
        this draft are governed by
        <a href="https://www.w3.org/community/about/process/cla">
          Community Contributor License Agreement (CLA)</a>, as specified by the
        <a href="https://www.w3.org/community/about/process/#cgroups">W3C Community Group Process</a>.
      </p>
      <p>
        While not a W3C recommendation, this classification is intended to
        clarify that, after extensive consensus-building, this specification is
        intended for implementation.
      </p>
      <p>
        <strong>This specification is considered stable</strong>. Further
        updates will be provided in superseding specifications.
      </p>
    <p>
    <a href="https://github.com/design-tokens/community-group/issues/">GitHub Issues</a> are preferred for
          discussion of this specification.
        
    
  </p></section><nav id="toc"><h2 class="introductory" id="table-of-contents">Table of Contents</h2><ol class="toc"><li class="tocline"><a class="tocxref" href="#abstract">Abstract</a></li><li class="tocline"><a class="tocxref" href="#sotd">Status of This Document</a></li><li class="tocline"><a class="tocxref" href="#modules"><bdi class="secno">1. </bdi>Modules</a></li><li class="tocline"><a class="tocxref" href="#resources"><bdi class="secno">2. </bdi>Resources</a></li><li class="tocline"><a class="tocxref" href="#acknowledgements"><bdi class="secno">A. </bdi>Acknowledgements</a></li></ol></nav>
    <section id="modules"><div class="header-wrapper"><h2 id="x1-modules"><bdi class="secno">1. </bdi>Modules</h2><a class="self-link" href="#modules" aria-label="Permalink for Section 1."></a></div>
      
      <p>The Design Tokens specification is composed of multiple modules:</p>
      <ul>
        <li>
          <a href="./format/">Format</a>
        </li>
        <li><a href="./color/">Color</a></li>
        <li><a href="./resolver/">Resolver</a></li>
      </ul>
    </section>
    <section id="resources"><div class="header-wrapper"><h2 id="x2-resources"><bdi class="secno">2. </bdi>Resources</h2><a class="self-link" href="#resources" aria-label="Permalink for Section 2."></a></div>
<ul>
<li><a href="https://github.com/design-tokens/community-group/blob/main/CODE_OF_CONDUCT.md">Code of conduct</a></li>
</ul>
</section>

    <section class="appendix" id="acknowledgements"><div class="header-wrapper"><h2 id="a-acknowledgements"><bdi class="secno">A. </bdi>Acknowledgements</h2><a class="self-link" href="#acknowledgements" aria-label="Permalink for Appendix A."></a></div>
      
      <p>
        We'd also like to thank the following contributors:
        <span id="gh-contributors">Abhishek Warokar, Adam Stankiewicz, Adekunle Oduye, Ale Muñoz, Asher, Benjamin Kindle, Bjørn Madsen, Chase McCoy, Copilot, Dale Sande, Daniel Flynn, Daniel Rinehart, Danny Banks, Dominique Hazael-Massieux, Evan Lovely, Fabian Friedl, Guilherme Nagüeva, Guy Lepage, Ivan Maksimovic, James Nash, Jan Toman, Jina Anne, Jon Levine, Joren Broekema, Kaelig Deloumeau-Prigent, Kevin Powell, Kilian Valkhof, KLS, Laurent Thiebault, Lukas Oppermann, Marc Edwards, Marcos Castro, Mark Tomlinson, Matt Felten, Matt Ström-Awn, Miriam Suzanne, Namık Özgür Aydın, nicolaibach, Nicolaos Skimas, Pavel Laptev, Pavel Vostrikov, Red Huang, Rob Eisenberg, Robin, Roman Komarov, Salem Cobalt, Sébastien Barbieri, Sigurd Fosseng, Stuart Robson, Vsevolod Dolgopolov (aka Seva), and Zhihao Cui</span>.
      </p>
    </section>
  

<p role="navigation" id="back-to-top">
    <a href="#title"><abbr title="Back to Top">↑</abbr></a>
  </p><script id="respec-highlight-vars">(() => {
// @ts-check

if (document.respec) {
  document.respec.ready.then(setupVarHighlighter);
} else {
  setupVarHighlighter();
}

function setupVarHighlighter() {
  document
    .querySelectorAll("var")
    .forEach(varElem => varElem.addEventListener("click", highlightListener));
}

function highlightListener(ev) {
  ev.stopPropagation();
  const { target: varElem } = ev;
  const hightligtedElems = highlightVars(varElem);
  const resetListener = () => {
    const hlColor = getHighlightColor(varElem);
    hightligtedElems.forEach(el => removeHighlight(el, hlColor));
    [...HL_COLORS.keys()].forEach(key => HL_COLORS.set(key, true));
  };
  if (hightligtedElems.length) {
    document.body.addEventListener("click", resetListener, { once: true });
  }
}

// availability of highlight colors. colors from var.css
const HL_COLORS = new Map([
  ["respec-hl-c1", true],
  ["respec-hl-c2", true],
  ["respec-hl-c3", true],
  ["respec-hl-c4", true],
  ["respec-hl-c5", true],
  ["respec-hl-c6", true],
  ["respec-hl-c7", true],
]);

function getHighlightColor(target) {
  // return current colors if applicable
  const { value } = target.classList;
  const re = /respec-hl-\w+/;
  const activeClass = re.test(value) && value.match(re);
  if (activeClass) return activeClass[0];

  // first color preference
  if (HL_COLORS.get("respec-hl-c1") === true) return "respec-hl-c1";

  // otherwise get some other available color
  return [...HL_COLORS.keys()].find(c => HL_COLORS.get(c)) || "respec-hl-c1";
}

function highlightVars(varElem) {
  const textContent = norm(varElem.textContent);
  const parent = varElem.closest(".algorithm, section");
  const highlightColor = getHighlightColor(varElem);

  const varsToHighlight = [...parent.querySelectorAll("var")].filter(
    el =>
      norm(el.textContent) === textContent &&
      el.closest(".algorithm, section") === parent
  );

  // update availability of highlight color
  const colorStatus = varsToHighlight[0].classList.contains("respec-hl");
  HL_COLORS.set(highlightColor, colorStatus);

  // highlight vars
  if (colorStatus) {
    varsToHighlight.forEach(el => removeHighlight(el, highlightColor));
    return [];
  } else {
    varsToHighlight.forEach(el => addHighlight(el, highlightColor));
  }
  return varsToHighlight;
}

function removeHighlight(el, highlightColor) {
  el.classList.remove("respec-hl", highlightColor);
  // clean up empty class attributes so they don't come in export
  if (!el.classList.length) el.removeAttribute("class");
}

function addHighlight(elem, highlightColor) {
  elem.classList.add("respec-hl", highlightColor);
}

/**
 * Same as `norm` from src/core/utils, but our build process doesn't allow
 * imports in runtime scripts, so duplicated here.
 * @param {string} str
 */
function norm(str) {
  return str.trim().replace(/\s+/g, " ");
}
})()</script><script id="respec-dfn-panel">(() => {
// @ts-check
if (document.respec) {
  document.respec.ready.then(setupPanel);
} else {
  setupPanel();
}

function setupPanel() {
  const listener = panelListener();
  document.body.addEventListener("keydown", listener);
  document.body.addEventListener("click", listener);
}

function panelListener() {
  /** @type {HTMLElement} */
  let panel = null;
  return event => {
    const { target, type } = event;

    if (!(target instanceof HTMLElement)) return;

    // For keys, we only care about Enter key to activate the panel
    // otherwise it's activated via a click.
    if (type === "keydown" && event.key !== "Enter") return;

    const action = deriveAction(event);

    switch (action) {
      case "show": {
        hidePanel(panel);
        /** @type {HTMLElement} */
        const dfn = target.closest("dfn, .index-term");
        panel = document.getElementById(`dfn-panel-for-${dfn.id}`);
        const coords = deriveCoordinates(event);
        displayPanel(dfn, panel, coords);
        break;
      }
      case "dock": {
        panel.style.left = null;
        panel.style.top = null;
        panel.classList.add("docked");
        break;
      }
      case "hide": {
        hidePanel(panel);
        panel = null;
        break;
      }
    }
  };
}

/**
 * @param {MouseEvent|KeyboardEvent} event
 */
function deriveCoordinates(event) {
  const target = /** @type HTMLElement */ (event.target);

  // We prevent synthetic AT clicks from putting
  // the dialog in a weird place. The AT events sometimes
  // lack coordinates, so they have clientX/Y = 0
  const rect = target.getBoundingClientRect();
  if (
    event instanceof MouseEvent &&
    event.clientX >= rect.left &&
    event.clientY >= rect.top
  ) {
    // The event probably happened inside the bounding rect...
    return { x: event.clientX, y: event.clientY };
  }

  // Offset to the middle of the element
  const x = rect.x + rect.width / 2;
  // Placed at the bottom of the element
  const y = rect.y + rect.height;
  return { x, y };
}

/**
 * @param {Event} event
 */
function deriveAction(event) {
  const target = /** @type {HTMLElement} */ (event.target);
  const hitALink = !!target.closest("a");
  if (target.closest("dfn:not([data-cite]), .index-term")) {
    return hitALink ? "none" : "show";
  }
  if (target.closest(".dfn-panel")) {
    if (hitALink) {
      return target.classList.contains("self-link") ? "hide" : "dock";
    }
    const panel = target.closest(".dfn-panel");
    return panel.classList.contains("docked") ? "hide" : "none";
  }
  if (document.querySelector(".dfn-panel:not([hidden])")) {
    return "hide";
  }
  return "none";
}

/**
 * @param {HTMLElement} dfn
 * @param {HTMLElement} panel
 * @param {{ x: number, y: number }} clickPosition
 */
function displayPanel(dfn, panel, { x, y }) {
  panel.hidden = false;
  // distance (px) between edge of panel and the pointing triangle (caret)
  const MARGIN = 20;

  const dfnRects = dfn.getClientRects();
  // Find the `top` offset when the `dfn` can be spread across multiple lines
  let closestTop = 0;
  let minDiff = Infinity;
  for (const rect of dfnRects) {
    const { top, bottom } = rect;
    const diffFromClickY = Math.abs((top + bottom) / 2 - y);
    if (diffFromClickY < minDiff) {
      minDiff = diffFromClickY;
      closestTop = top;
    }
  }

  const top = window.scrollY + closestTop + dfnRects[0].height;
  const left = x - MARGIN;
  panel.style.left = `${left}px`;
  panel.style.top = `${top}px`;

  // Find if the panel is flowing out of the window
  const panelRect = panel.getBoundingClientRect();
  const SCREEN_WIDTH = Math.min(window.innerWidth, window.screen.width);
  if (panelRect.right > SCREEN_WIDTH) {
    const newLeft = Math.max(MARGIN, x + MARGIN - panelRect.width);
    const newCaretOffset = left - newLeft;
    panel.style.left = `${newLeft}px`;
    /** @type {HTMLElement} */
    const caret = panel.querySelector(".caret");
    caret.style.left = `${newCaretOffset}px`;
  }

  // As it's a dialog, we trap focus.
  // TODO: when <dialog> becomes a implemented, we should really
  // use that.
  trapFocus(panel, dfn);
}

/**
 * @param {HTMLElement} panel
 * @param {HTMLElement} dfn
 * @returns
 */
function trapFocus(panel, dfn) {
  /** @type NodeListOf<HTMLAnchorElement> elements */
  const anchors = panel.querySelectorAll("a[href]");
  // No need to trap focus
  if (!anchors.length) return;

  // Move focus to first anchor element
  const first = anchors.item(0);
  first.focus();

  const trapListener = createTrapListener(anchors, panel, dfn);
  panel.addEventListener("keydown", trapListener);

  // Hiding the panel releases the trap
  const mo = new MutationObserver(records => {
    const [record] = records;
    const target = /** @type HTMLElement */ (record.target);
    if (target.hidden) {
      panel.removeEventListener("keydown", trapListener);
      mo.disconnect();
    }
  });
  mo.observe(panel, { attributes: true, attributeFilter: ["hidden"] });
}

/**
 *
 * @param {NodeListOf<HTMLAnchorElement>} anchors
 * @param {HTMLElement} panel
 * @param {HTMLElement} dfn
 * @returns
 */
function createTrapListener(anchors, panel, dfn) {
  const lastIndex = anchors.length - 1;
  let currentIndex = 0;
  return event => {
    switch (event.key) {
      // Hitting "Tab" traps us in a nice loop around elements.
      case "Tab": {
        event.preventDefault();
        currentIndex += event.shiftKey ? -1 : +1;
        if (currentIndex < 0) {
          currentIndex = lastIndex;
        } else if (currentIndex > lastIndex) {
          currentIndex = 0;
        }
        anchors.item(currentIndex).focus();
        break;
      }

      // Hitting "Enter" on an anchor releases the trap.
      case "Enter":
        hidePanel(panel);
        break;

      // Hitting "Escape" returns focus to dfn.
      case "Escape":
        hidePanel(panel);
        dfn.focus();
        return;
    }
  };
}

/** @param {HTMLElement} panel */
function hidePanel(panel) {
  if (!panel) return;
  panel.hidden = true;
  panel.classList.remove("docked");
}
})()</script><script src="https://www.w3.org/scripts/TR/2021/fixup.js"></script></body></html>